<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<HTML>
<HEAD>
 <META NAME="GENERATOR" CONTENT="SGML-Tools 1.0.7">
 <TITLE>SDCC Compiler User Guide: Interfacing with assembly routines.</TITLE>
 <LINK HREF="SDCCUdoc-22.html" REL=next>
 <LINK HREF="SDCCUdoc-20.html" REL=previous>
 <LINK HREF="SDCCUdoc.html#toc21" REL=contents>
</HEAD>
<BODY>
<A HREF="SDCCUdoc-22.html">Next</A>
<A HREF="SDCCUdoc-20.html">Previous</A>
<A HREF="SDCCUdoc.html#toc21">Contents</A>
<HR>
<H2><A NAME="Interface_asm"></A> <A NAME="s21">21. Interfacing with assembly routines.</A> </H2>

<H2><A NAME="ss21.1">21.1 Global registers used for parameter passing.</A>
 </H2>

<P>By default the compiler uses the global registers "DPL,DPH,B,ACC" to pass
the first parameter to a routine, the second parameter onwards is either allocated
on the stack (for reentrant routines or --stack-auto is used) or in the internal
/ external ram (depending on the memory model). 
<H3>Assembler routine non-reentrant </H3>

<P>In the following example the function<B> cfunc</B> calls an assembler routine
<B>asm_func</B>, which takes two parameters.
<P>extern int asm_func( unsigned short, unsigned short);
<P>
<PRE>
 
int c_func (unsigned short i, unsigned short j) 
{ 
        return
 asm_func(i,j); 
} 
int main() 
{ 
   return c_func(10,9); 
}
 
</PRE>
<P>The corresponding assembler function is:-
<P>
<PRE>
        .globl _asm_func_PARM_2 
        .globl _asm_func 
        .area
 OSEG 
_asm_func_PARM_2:       .ds      1 
        .area CSEG 
_asm_func: 
       
 mov     a,dpl 
        add     a,_asm_func_PARM_2 
        mov     dpl,a 
       
 mov     dpl,#0x00 
        ret
 
</PRE>
<P>Note here that the return values are placed in 'dpl' - One byte return
value, 'dpl' LSB &amp; 'dph' MSB for two byte values. 'dpl', 'dph' and 'b'
for three byte values (generic pointers) and 'dpl','dph','b' &amp; 'acc' for
four byte values.
<P>The parameter naming convention is <B>_&lt;function_name&gt;_PARM_&lt;n&gt;,</B>
where n is the parameter number starting from 1, and counting from the left.
The first parameter is passed in "dpl" for One bye parameter, "dptr" if two bytes,
"b,dptr" for three bytes and "acc,b,dptr" for four bytes, the <CODE></CODE><CODE><B>varaible name for
the second parameter will be _&lt;function_name&gt;_PARM_2.</B></CODE>
<P>Assemble the assembler routine with the following command.
<P>
<PRE>
asx8051 -losg asmfunc.asm
 
</PRE>
<P>Then compile and link the assembler routine to the C source file with the
following command,
<P>
<PRE>
sdcc cfunc.c asmfunc.rel
 
</PRE>
<H3>Assembler routine is reentrant </H3>

<P>In this case the second parameter onwards will be passed on the stack ,
the parameters are pushed from right to left i.e. after the call the left most
parameter will be on the top of the stack. Here is an example.
<P>extern int asm_func( unsigned short, unsigned short);
<P>
<PRE>
 int c_func (unsigned short i, unsigned short j) reentrant 
{ 
       
 return asm_func(i,j); 
} 
int main() 
{ 
   return c_func(10,9);
 
}
 
</PRE>
<P>The corresponding assembler routine is.
<P>
<PRE>
        .globl _asm_func 
_asm_func: 
        push  _bp 
        mov  _bp,sp
 
        mov  r2,dpl
        mov  a,_bp 
        clr  c 
        add  a,#0xfd
 
        mov  r0,a 
        add  a,#0xfc
        mov  r1,a 
        mov 
 a,@r0 
        add  a,r2
        mov  dpl,a 
        mov  dph,#0x00 
       
 mov  sp,_bp 
        pop  _bp 
        ret
 
</PRE>
<P>The compiling and linking procedure remains the same, however note the
extra entry &amp; exit linkage required for the assembler code, _bp is the
stack frame pointer and is used to compute the offset into the stack for parameters
and local variables.
<H2><A NAME="ss21.2">21.2 With --noregparms option.</A>
 </H2>

<P>When the source is compiled with --noregparms option , space is allocated
for each of the parameters passed to a routine.
<H3>Assembler routine non-reentrant. </H3>

<P>In the following example the function<B> cfunc</B> calls an assembler routine
<B>asm_func</B>, which takes two parameters.
<P>
<PRE>
extern int asm_func( unsigned short, unsigned short); 
int c_func (unsigned short i, unsigned short j) 
{ 
        return
 asm_func(i,j); 
} 
int main() 
{ 
   return c_func(10,9); 
}
 
</PRE>
<P>The corresponding assembler function is:-
<P>
<PRE>
        .globl _asm_func_PARM_1 
        .globl _asm_func_PARM_2 
       
 .globl _asm_func 
        .area OSEG 
_asm_func_PARM_1:       .ds     1 
_asm_func_PARM_2:      
 .ds      1 
        .area CSEG 
_asm_func: 
        mov     a,_asm_func_PARM_1
 
        add     a,_asm_func_PARM_2 
        mov     dpl,a 
        mov    
 dpl,#0x00 
        ret
 
</PRE>
<P>Note here that the return values are placed in 'dpl' - One byte return
value, 'dpl' LSB &amp; 'dph' MSB for two byte values. 'dpl', 'dph' and 'b'
for three byte values (generic pointers) and 'dpl','dph','b' &amp; 'acc' for
four byte values.
<P>The parameter naming convention is <B>_&lt;function_name&gt;_PARM_&lt;n&gt;,</B>
where n is the parameter number starting from 1, and counting from the left.
i.e. the <CODE></CODE><CODE><B>left-most parameter name will be _&lt;function_name&gt;_PARM_1.</B></CODE>
<P>Assemble the assembler routine with the following command.
<P>
<PRE>
asx8051 -losg asmfunc.asm
 
</PRE>
<P>Then compile and link the assembler routine to the C source file with the
following command,
<P>
<PRE>
sdcc cfunc.c asmfunc.rel
 
</PRE>
<H3>Assembler routine is reentrant. </H3>

<P>In this case the parameters will be passed on the stack , the parameters
are pushed from right to left i.e. after the call the left most parameter will
be on the top of the stack. Here is an example.
<P>extern int asm_func( unsigned short, unsigned short);
<P>
<PRE>
 int c_func (unsigned short i, unsigned short j) reentrant 
{ 
       
 return asm_func(i,j); 
} 
int main() 
{ 
   return c_func(10,9);
 
}
 
</PRE>
<P>The corresponding assembler routine is.
<P>
<PRE>
        .globl _asm_func 
_asm_func: 
        push  _bp 
        mov  _bp,sp
 
        mov  a,_bp 
        clr  c 
        add  a,#0xfd 
        mov 
 r0,a 
        mov  a,_bp 
        clr  c 
        add  a,#0xfc 
       
 mov  r1,a 
        mov  a,@r0 
        add  a,@r1 
        mov  dpl,a 
       
 mov  dph,#0x00 
        mov  sp,_bp 
        pop  _bp 
        ret
 
</PRE>
<P>The compiling and linking procedure remains the same, however note the
extra entry &amp; exit linkage required for the assembler code, _bp is the
stack frame pointer and is used to compute the offset into the stack for parameters
and local variables.
<HR>
<A HREF="SDCCUdoc-22.html">Next</A>
<A HREF="SDCCUdoc-20.html">Previous</A>
<A HREF="SDCCUdoc.html#toc21">Contents</A>
</BODY>
</HTML>
